<template>
  <section v-loading="loading">
    <el-form>
      <el-form-item>
        <el-button type="primary" @click="initDigitalHuman">一键开播</el-button>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="getContentForLargeModel">请求大模型</el-button>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="quertIsSend">查询音频队列</el-button>
      </el-form-item>
      <el-form-item>
        <el-input v-model.trim="message" type="textarea" :rows="1" style="width: 400px; margin-right: 10px"></el-input>
        <el-button type="primary" @click="sendText">发送文本</el-button>
      </el-form-item>
      <el-form-item>
        <FieldControlCom @triggerKeywordsFn="triggerKeywordsFn"></FieldControlCom>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="save">添加数据</el-button>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="list">获取数据</el-button>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="remove">删除数据</el-button>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="page">获取分页数据</el-button>
      </el-form-item>

      <el-form-item>
        <el-input v-model.trim="yourQuestion" type="text" placeholder="请输入您的问题" :rows="1"
          style="width: 400px; margin-right: 10px"></el-input>
        <el-button type="primary" @click="sendYourQuestion">发送</el-button>
      </el-form-item>
    </el-form>
  </section>
</template>

<script setup>
import { onMounted, onUnmounted, reactive, ref } from "vue";
import { useAppStore } from "@/store/index";
import { ElMessage } from "element-plus";
import { ipcApiRoute } from "@/api/main";
import { ipc } from "@/utils/ipcRenderer";
import axios from "axios";
import FieldControlCom from "@/components/FieldControlCom/index.vue";

const store = useAppStore();

const path = require("path");
const fs = require("fs");

const net = window.require("net");
const socket = new net.Socket();
// const socket = io('127.0.0.1:12345')
const servicAddress = "127.0.0.1";
const port = "12345";
const num = ref(0);
const digitalId = ref("test");
const timer = ref(null);
const queryAudioTimer = ref(null);
const queryAudioData = reactive({
  data: {},
});
const message = ref("");

const yourQuestion = ref("");

const loading = ref(false);
const folderPath =
  "D:\\dh-runtime/wav2lip/wav2lip/realtime/rtmp_server/push_stream/face_npy/test1";
const fileName = "final_output.txt";

// 初始化数字人指令
const INIT_DIGITAL = ref("INIT_DIGITAL_HUMAN:test1:wav2lip");

// 启动本地播放器指令
const START_LOCAL = "START_STREAMING:local";

// 音频指令
const AUDIO_DIRECT = "TRANSMIT_AUDIO_FILE:D:\\9s.wav";

// 默认音频
const audioList = ref([
  {
    label: "音频1",
    path: "D:\\9s.wav",
  },
  {
    label: "音频2",
    path: "D:\\ff6.wav",
  },
  {
    label: "音频3",
    path: "D:\\1ba.wav",
  },
  {
    label: "音频4",
    path: "D:\\5bd.wav",
  },
]);

// 触发关键字音频
const keywordsAudio = ref([
  {
    label: "like",
    path: "D:\\like.wav",
  },
  {
    label: "haha",
    path: "D:\\haha.wav",
  },
  {
    label: "guanzhu",
    path: "D:\\guanzhu.wav",
  },
  {
    label: "lihai",
    path: "D:\\lihai.wav",
  },
  {
    label: "6",
    path: "D:\\6.wav",
  },
]);

// const changeDigitalId = (id) => {
//     folderPath.value = `D:\\dh-runtime/wav2lip/wav2lip/realtime/rtmp_server/push_stream/face_npy/${val}`
//     INIT_DIGITAL.value = `INIT_DIGITAL_HUMAN:${digitalId.value}:wav2lip`
//     console.log("INIT_DIGITAL.value", INIT_DIGITAL.value)
// }

// 触发关键字音频
const triggerKeywordsFn = (keywordsData) => {
  const { key } = keywordsData;
  console.log("keywordsData-----", keywordsData);
  const obj = keywordsAudio.value.find((item) => item.label == key);
  const path = obj.path;
  const direct = `TRANSMIT_AUDIO_FILE:${path}`;
  console.log("触发关键字音频---direct", direct);
  sendDirect(direct);
};

const handleNpyBat = () => {
  const batPath = "D:\\ms-ge.bat";
  const videoPath = "D:\\test1.mp4";
  const outfolderName = "test1";

  const isExitOutTxt = checkIfFileExists([folderPath], fileName);
  console.log("isExitOutTxt----", isExitOutTxt);

  if (!isExitOutTxt) {
    const d = `${batPath} ${videoPath} ${outfolderName}`;
    ipc
      .invoke(ipcApiRoute.openBatFile, { batPath, videoPath, outfolderName })
      .then((res) => {
        console.log("handleNpyBat----->", res);
        loading.value = true;
        checkIsExist();
      });
  }
};

// const checkFileExists = ({ folderPath, fileName }) => {
//   console.log("checkFileExists====", folderPath, fileName);
//   // 构建完整的文件路径
//   const filePath = path.join(folderPath, fileName);

//   console.log("filePath", filePath);
//   // 尝试访问文件
//   fs.access(filePath, fs.constants.F_OK, (err) => {
//     console.log("err", !err);
//     if (!err) {
//       loading.value = false;
//       if (timer.value) {
//         clearInterval(timer.value);
//       }
//       ElMessage.success(`${fileName}文件已生成`);
//       console.log("文件已生成");
//     } else {
//       console.log("文件不存在");
//     }
//     return !err;
//   });
// };

const checkIsExist = () => {
  timer.value = setInterval(() => {
    checkIfFileExists({ folderPath, fileName });
  }, 3000);

  // ipc.invoke(ipcApiRoute.checkFileExists, { folderPath, fileName }).then(res => {
  //     console.log("checkIsExist----->",res)
  //     // if (!res) {
  //     //     checkIsExist()
  //     // }
  // })
};

// 检查文件是否存在的函数
const checkIfFileExists = (folderPaths, filename) => {
  return folderPaths.every((folderPath) => {
    const filePath = path.join(folderPath, filename);
    return fs.existsSync(filePath);
  });
};

const initDigitalHuman = () => {
  loading.value = true;
  const directs = [INIT_DIGITAL.value, START_LOCAL, AUDIO_DIRECT];
  if (directs[num.value]) {
    sendDirect(directs[num.value]);
  }
  
};

const socketInit = () => {
  socket.connect(port, servicAddress, () => {
    console.log(
      "连接socket成功:" + num.value + ", socket地址" + servicAddress + ":" + port
    );
    if (num.value > 0 && num.value < 3) {
      initDigitalHuman();
    }

    console.log("queryAudioData", queryAudioData.data);
    if (queryAudioData.data) {
      if (+queryAudioData.data.pushqueue * 2 <= 4) {
        // 可以继续发送音频
        sendAudio();
        // isSendAudio.value = true
      }
    }
  });
};

const sendDirect = (message) => {
  socket.write(message);
  console.log(`发送消息--${message}--成功---`);
};

const socketData = () => {
  socket.on("data", (data) => {
    console.log("-----------------------");
    console.log("接收到数据:");
    const rstObj = parseBufferToObjectWithRegex(data);
    console.log(rstObj);
    const is200 = rstObj.statecode == "200";
    loading.value = false;

    if (is200) {
      num.value += 1;
      if (rstObj.pushqueue) {
        Object.assign(queryAudioData.data, rstObj);
      } else {
        queryAudioData.data = {};
      }
      console.log("queryAudioData=======", queryAudioData.data);
    } else {
      ElMessage.error(`接受socket返回消息：${data.toString()}`);
    }
  });
};

const parseBufferToObjectWithRegex = (buffer) => {
  // 将 buffer 转换为字符串并去除首尾空白字符
  let dataString = buffer.toString("utf-8").trim();

  // 正则表达式匹配所有键值对 (键和值之间用 ":" 分隔，允许值为空)
  let resultObject = {};
  let regex = /\s*([^:]+)\s*:\s*([^:]*?)\s*(?=\s*:|$)/g; // 允许值为空
  let match;

  // 使用 exec 循环查找所有匹配的键值对
  while ((match = regex.exec(dataString)) !== null) {
    // 如果值为空，则给定空字符串作为默认值
    resultObject[match[1].trim()] = match[2].trim() || ""; // 如果没有值，设置为 ""
  }

  return resultObject;
};

const socketClose = () => {
  socket.on("close", () => {
    console.log("链接关闭:", num.value);
    // if(num.value > 0 && num.value < 3){
    socketInit();
    // }else{
    //
    // }
    if (num.value == 3) {
      loading.value = false;
    }
  });
};

const socketError = () => {
  socket.on("error", (err) => {
    console.log("socketError----->", err);

    if (err.code === "ECONNRESET") {
      console.error("Connection reset by peer");
      // 在这里可以实现重试逻辑或其他错误处理
    } else {
      console.error("Socket error:", err);
    }
  });
};

// 发送文本转语音
const sendText = () => {
  if (!message.value.trim()) {
    ElMessage.error("请输入文本内容");
    return;
  }
  const audio_save_filename = `音频${audioList.value.length + 1}.wav`;
  axios
    .post("http://127.0.0.1:9670/synthesize", {
      models_name: "meiqi", // 声音模型
      audio_save_path: "D:\\", // 保存路径
      audio_save_filename: audio_save_filename, // 保存文件名
      text: message.value, // 文本内容
      length_scale: 1.1, // 语速
      comma_pause: 0.3, // 逗号停顿
      period_pause: 0.5, // 句号停顿
      priority: 1, //0是代表高级 1是代表低级 默认是1
    })
    .then((res) => {
      console.log("sendText----->", res);
      if (res.status == 200) {
        const { data } = res;
        const audioItem = {
          path: data.audio_path,
          name: audio_save_filename,
        };
        const AUDIO_DIRECT = `TRANSMIT_AUDIO_FILE:${data.audio_path}`;
        console.log("发送音频指令sendText：", AUDIO_DIRECT);
        sendDirect(AUDIO_DIRECT);
        // audioList.value.push(audioItem)
        message.value = "";
      }
    });
};

const goodsDesc =
  "您是一位充满活力和热情的直播主播，请根据以下要求和产品介绍，编写一段吸引人的真实带货话术。话术要求：1.避免使用“结束直播”或者“下播”或者“离开直播间”的直接措辞，避免使用表示告别的常用短语，避免暗示直播结束的任何用语；2.话术结尾以【家人们！感谢大家一直陪伴着我们直播间啊！我们会继续努力为大家带来更多好物和惊喜的！千万不要离开直播间哦！】结束，可以对这段话进行改写，和上文自然衔接；3.请确保生成的内容中不包含任何形式的括号，包括小括号（()）、中括号（[]）和大括号（{ }）；4.亲切地称呼观众为【家人们】，以增强亲切感和归属感；5.避免使用【早上好】、【中午好】、【晚上好】等具体时间问候语，以适应不同时间段的直播；我们直播间每天都会为大家带来各种好物和优惠活动，相信总有一款会让你心动的。所以，赶紧关注我们吧！”结尾。6.围绕产品介绍，编写一篇约1500字左右的直播话术，销售风格。7.话术不能包含极限词，如第一，唯一，独一，首个，首选，首发，领袖，巅峰，最高等词、广告违禁词如一盒见效、彻底康复等词。8.话术不能包含秒杀，送礼品等诱导消费的词语。产品介绍：产品名：深层补水保湿直播间专属价格：15.9元市场价:298元产品优势：这是针对皮肤补水的热门项目，几乎所有顾客都非常喜欢，想要皮肤变得滋润，变得更白更嫩，一定要拍这个，体验过后就会知道有多好适用人群：男女通用";

// 请求大模型
const getContentForLargeModel = () => {
  axios
    .post(
      "https://qianfan.baidubce.com/v2/chat/completions",
      {
        model: "ernie-3.5-8k",
        messages: [
          {
            role: "user",
            content: "你好",
          },
          {
            role: "user",
            content: goodsDesc,
          },
        ],
      },
      {
        headers: {
          "Content-Type": "application/json", // 设置请求头为 JSON
          Authorization:
            "Bearer bce-v3/ALTAK-2MSmwG0QsS8A7CwtYCoa4/b8d7ebc508b4173ad9bc6ff9534f0ea0e77d4a70", // 例如设置 Bearer Token
        },
      }
    )
    .then((res) => {
      console.log("getContentForLargeModel----->", res.data);
      const { choices } = res.data;
      const defaultText = choices.map((item) => item.message.content).join("\n");
      store.updateState({
        defaultText,
      });

      console.log("defaultText", store.defaultText);
    });
};

const sendYourQuestion = () => {
  if (!yourQuestion.value.trim()) {
    ElMessage.error("请输入文本内容");
    return;
  }

  axios
    .post(
      "https://qianfan.baidubce.com/v2/app/conversation/runs",
      {
        app_id: "c79e0239-f894-4830-9484-45a471f328cf",
        query: yourQuestion.value,
        conversation_id: "3f5ae026-deba-4036-91bb-deee7ee27fde",
        stream: true,
      },
      {
        headers: {
          "Content-Type": "application/json", // 设置请求头为 JSON
          Authorization:
            "Bearer bce-v3/ALTAK-2MSmwG0QsS8A7CwtYCoa4/b8d7ebc508b4173ad9bc6ff9534f0ea0e77d4a70", // 例如设置 Bearer Token
        },
      }
    )
    .then((response) => {
      console.log("sendYourQuestion----->", response.data);
    });
};

const sendAudio = () => {
  const item = getRandomElement();
  console.log("getRandomElement", item);
  const AUDIO_DIRECT = `TRANSMIT_AUDIO_FILE:${item.path}`;
  console.log("发送音频指令：", AUDIO_DIRECT);
  sendDirect(AUDIO_DIRECT);
};

// 查询队列指令
const quertIsSend = () => {
  sendDirect("QUERY_QUEUE_LENGTH");
  queryAudioTimer.value = setInterval(() => {
    sendDirect("QUERY_QUEUE_LENGTH");
  }, 8000);
};

//  音频数组中随机取音频
const getRandomElement = () => {
  let randomElement = null;
  randomElement = audioList.value[Math.floor(Math.random() * audioList.value.length)];
  return randomElement;
};

// 手动关闭连接
const destroyTcp = () => {
  socket.destroy();
};

onMounted(() => {
  // 执行bat脚本，生成npy文件
  handleNpyBat();
  // socket连接
  socketInit();
  socketData();
  socketClose();
  socketError();
  //一般是在组件挂载完成后初始化表结构
  initAnchorModelTable();
});

onUnmounted(() => {
  console.log("组件销毁2222");
  // 销毁socket
  // destroyTcp()
});

const initAnchorModelTable = () => {
  const params = {
    action: "getDataDir",
  };
  ipc.invoke(ipcApiRoute.sqlitedbOperation, params).then((res) => {
    if (res.code == -1) {
      ElMessage.error("请检查sqlite是否正确安装");
      return;
    }
    console.log(res);
  });
};

//获取所有数据
const list = () => {
  const params = {
    action: "list",
  };
  ipc.invoke(ipcApiRoute.sqlitedbOperation, params).then((res) => {
    ElMessage.success(JSON.stringify(res));
    return;
  });
};

//保存数据
const save = () => {
  const params = {
    action: "save",
    info: {
      name: "test",
      age: 18,
    },
  };
  ipc.invoke(ipcApiRoute.sqlitedbOperation, params).then((res) => {
    ElMessage.success(JSON.stringify(res));
    return;
  });
};

//删除数据
const remove = () => {
  const params = {
    action: "remove",
  };
  ipc.invoke(ipcApiRoute.sqlitedbOperation, params).then((res) => {
    ElMessage.success(JSON.stringify(res));
    return;
  });
};

const page = () => {
  const params = {
    action: "page",
    page: 1,
    pageSize: 10,
  };
  ipc.invoke(ipcApiRoute.sqlitedbOperation, params).then((res) => {
    console.log(res);
    ElMessage.success(JSON.stringify(res));
    return;
  });
};
</script>

<style lang="less" scoped></style>
